package com.youlu.campus.service.activity;

import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.common.utils.ShotUrlUtil;
import com.youlu.campus.common.utils.TimeUtils;
import com.youlu.campus.entity.ActivityChannelStatistics;
import com.youlu.campus.entity.ActivityInfo;
import com.youlu.campus.entity.HuoLinkerInfo;
import com.youlu.campus.entity.PlatformConfig;
import com.youlu.campus.entity.VO.req.ActivityChannelPvUvQueryReq;
import com.youlu.campus.entity.VO.req.ActivityChannelStatisticsCommandReq;
import com.youlu.campus.entity.VO.req.ActivityChannelStatisticsPVUVReq;
import com.youlu.campus.entity.VO.req.ActivityChannelStatisticsQueryReq;
import com.youlu.campus.entity.VO.res.ActivityChannelPvUvRes;
import com.youlu.campus.entity.statistics.ActivityChannelPageElementStatistics;
import com.youlu.campus.entity.statistics.vo.ChannelPageElementReq;
import com.youlu.campus.service.linker.HuoLinkerInfoService;
import com.youlu.campus.service.platform.PlatformConfigService;
import com.youlu.campus.service.statistics.ActivityChannelPageElementStatisticsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;

@Slf4j
@Service
public class ActivityChannelStatisticsService {

    private String activityProgressUrl = "/h4/index.html#/pages/activity-schedule?activityId=%s&theme=%s&appId=%s" +
            "&authorizeMode=%s&channel=%s";
    private String activityUrl = "/index.html?#/pages/activity-detial?activityId=%s&appId=%s&theme=%s" +
            "&authorizeMode=%s&channel=%s";
    private String activityUrl2 = "index.html?#/pages/activity-detial?activityId=%s&appId=%s&theme=%s&channel=%s" +
            "&authorizeMode=%s";
    //    private String activityUrl = "/h5/index.html?#/pages/activity-detial?activityId=%s&appId=%s&theme=%s" +
//            "&authorizeMode=%s";
    private String activityVoteUrl = "/v5/index.html?#/pages/activity-detial?activityId=%s&appId=%s&theme=%s" +
            "&authorizeMode=%s&channel=%s";
    /**
     * 新竞赛活动
     */
    private String activityContestPluUrl = "/c5/index.html?#/?appId=%s&activityId=%s&theme=%s&channel=%s";
    /**
     * 新竞赛活动进度链接
     */
    private String activityContestPlusProgressUrl = "/c5/index.html?#/pages/share-invitation?appId=%s&activityId=%s" +
            "&theme=&s&channel=%s";

    private String activityContestUrl = "/contest-h5/index.html?a=a#/pages/home?appId=%s&activityId=%s&channel=%s";
    /**
     * 收款链接
     */
    private String activityPayUrl = "/h5/#/pages/activity-reward?activityId=%s&appId=%s&theme=%s&authorizeMode=%s" +
            "&channel=%s";

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private PlatformConfigService platformConfigService;


    @Autowired
    private HuoLinkerInfoService huoLinkerInfoService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Value("${sys.constentActivity:61834be460d5e86411b654a5}")
    private String constentActivity;

    private static final String PV = "channel.activityId:%s:channel:%s.pv";

    private static final String UV = "channel.activityId:%s:channel:%s.uv";

    private static final String USER_UV = "channel.activityId:%s.channel:%s.cookie:%s.uv";

    @Autowired
    private ActivityChannelDayPVUVService activityChannelDayPVUVService;

    @Autowired
    private ActivityChannelHourPVUVService activityChannelHourPVUVService;

    @Autowired
    private ActivityChannelPageElementStatisticsService activityChannelPageElementStatisticsService;

    public static void main(String[] args) {
        System.out.println(RandomStringUtils.randomAlphabetic(6));
    }

    public List<ActivityChannelPvUvRes> listPvUv(ActivityChannelPvUvQueryReq req) {
        String activityId = req.getActivityId();
        String channelCode = req.getChannelCode();

        Query query = new Query();
        query.addCriteria(Criteria.where("activityId").is(activityId));
        query.addCriteria(Criteria.where("channelCode").is(channelCode));
        Date startTime = req.getStartTime();
        Date endTime = req.getEndTime();
        if (Objects.nonNull(startTime) && Objects.nonNull(endTime)) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            query.addCriteria(Criteria.where("dayDate").gte(Integer.valueOf(sdf.format(startTime))).lte(Integer.valueOf(sdf.format(endTime))));
        }
        if (req.getType() == 1) {
            return activityChannelDayPVUVService.list(query);
        }
        return activityChannelHourPVUVService.list(query);
    }


    @Async
    public void setSignUpChannel(String activityId, String channelCode) {
        if (StringUtils.isAnyBlank(activityId, channelCode)) {
            log.error("【统计渠道报名人数】activityId:{} |channelCode:{} 参数为空", activityId, channelCode);
            return;
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("channelCode").is(channelCode));
        query.addCriteria(Criteria.where("activityId").is(activityId));
        boolean exists = this.mongoTemplate.exists(query, ActivityChannelStatistics.class);
        if (!exists) {
            return;
        }
        Update update = new Update();
        update.inc("signUpCount", 1L);
        this.mongoTemplate.updateFirst(query, update, ActivityChannelStatistics.class);
        activityChannelDayPVUVService.setDaySignUp(activityId, channelCode);
        activityChannelHourPVUVService.setHourOfDaySignUp(activityId, channelCode);
    }

    public void addPVUV(ActivityChannelStatisticsPVUVReq req) {
        String activityId = req.getActivityId();
        String channelCode = req.getChannelCode();
        if (StringUtils.isAnyBlank(activityId, channelCode)) {
            log.error("【pv uv】activityId:{} |channelCode:{} 参数为空", activityId, channelCode);
            return;
        }
        activityChannelPageElementStatisticsService.channelPageElementStatistics(req);
        if (req.getType() == 1 && req.getSecond().compareTo(0D) == 0) {
            setPV(activityId, channelCode, 1L);
        }
        Long userUV = setUserUV(req.getClientCookie(), activityId, channelCode);
        log.info("渠道用户UV channel：{}|activityId：{}|cookie:{}|uv:{}", channelCode, activityId, req.getClientCookie(),
                userUV);
        if (userUV == 1L) {
            setUV(activityId, channelCode, 1L);
        }
        activityChannelDayPVUVService.doSetPVUV(activityId, channelCode, req.getClientCookie());
        activityChannelHourPVUVService.doSetPVUV(activityId, channelCode, req.getClientCookie());
    }

    public String generateShortUrl(String id) {
        log.info(":>>> 开始生成短链接:{}", id);
        if (StringUtils.isBlank(id)) {
            log.error(":>>> 主键ID为空");
            throw new BusinessException("主键ID为空");
        }
        ActivityChannelStatistics activityChannelStatistics = this.mongoTemplate.findById(id,
                ActivityChannelStatistics.class);
        String activityId = activityChannelStatistics.getActivityId();
        PlatformConfig platformConfig = platformConfigService.find();
        ActivityInfo activityInfo = activityService.findOne(activityId);
        String domain = "";
        String catalogue = "";
        String type = "";
        boolean newLinker = false;
        // 竞赛类的活动
        if (constentActivity.contains(id)) {
            domain = platformConfigService.getContestBizFrontDomain();
            catalogue = platformConfigService.getContestCatalogue();
            type = "C";
        } else {
            domain = platformConfigService.getBizFrontDomain();
            if ("contest-plus".equals(activityInfo.getType())) {
                catalogue = platformConfigService.getContestPlusCatalogue();
                type = "C-PLUS";
            } else if ("vote".equals(activityInfo.getType())) {
                catalogue = platformConfigService.getVoteCatalogue();
                type = "A";
            } else {
//               catalogue = platformConfigService.getCatalogue();
                type = "A";
                newLinker = true;
                // 2022-10-27 10:33:55的毫秒数:1666838035000L
                Integer hours = TimeUtils.getHours(new Date(1666838035000L), new Date());
                // 更新当前目录下标
                log.info(":>>> 当前时间:{} 小时数:{},当前目录标号:{}", new Date(), hours, platformConfig.getCurrentCatalogue());
                if (hours.compareTo(platformConfig.getCurrentCatalogue()) != 0) {
                    platformConfigService.updateCurrentCatalogue(platformConfig.getId(), hours);
                }
                catalogue = String.format(platformConfig.getMainCataloguePrefix(),
                        (platformConfig.getMainCatalogueMin() + hours));
                log.info(":>>> 生成的活动:{} 目录为:{}", id, catalogue);
            }
        }
        String wechatUrl = "";
        if ("jinshuju".equals(activityInfo.getType())) {
            catalogue = platformConfig.getJinCatalogue();
            long time = System.currentTimeMillis();
            domain = platformConfig.getJinBizFrontDomain();
            type = "J";
            wechatUrl =
                    domain + catalogue + "/index.html?a=1#/pages/index?scope=snsapi_base&activityId=" + activityInfo.getId() + "&channel=" + activityChannelStatistics.getChannelCode() + "&t=" + time;
        } else {
            wechatUrl = this.getWechatUrl(activityInfo, activityChannelStatistics.getChannelCode(), type);
        }
//        wechatUrl = platformConfigService.replaceActiveCatalogue(wechatUrl, catalogue, type);
        log.info(":>>> 活动:{},类型:{} 对应的链接为:{}", activityInfo.getId(), type, wechatUrl);
        String u = "";
        if ("jinshuju".equals(activityInfo.getType())) {
            u = wechatUrl;
        } else {
            u = String.format(wechatUrl, domain, "%s");
        }
        String shortUrl = ShotUrlUtil.shortUrl(u);
        if (!huoLinkerInfoService.exist(shortUrl)) {
            HuoLinkerInfo huoLinkerInfo = new HuoLinkerInfo();
            huoLinkerInfo.setActivityId(activityId);
            huoLinkerInfo.setBizType(type);
            huoLinkerInfo.setDomain(domain);
            huoLinkerInfo.setCreatedTime(new Date());
            huoLinkerInfo.setUrl(u);
            huoLinkerInfo.setKey(shortUrl);
            huoLinkerInfo.setCatalogue(catalogue);
            huoLinkerInfo.setVersion("V2");
            huoLinkerInfo.setActivityType(activityInfo.getType());
            huoLinkerInfoService.create(huoLinkerInfo);
        }
        log.info(":>>> 活动:{} 短链接地址为:{},对应长链接:{}", id, shortUrl, u);
        return shortUrl;
    }

    public Page<ActivityChannelStatistics> list(ActivityChannelStatisticsQueryReq activityChannelStatisticsQueryReq) {
        String activityId = activityChannelStatisticsQueryReq.getActivityId();
        Integer pageNo = activityChannelStatisticsQueryReq.getPageNo();
        Integer pageSize = activityChannelStatisticsQueryReq.getPageSize();
        ActivityInfo activityInfo = activityService.findOne(activityId);
        PageRequest pageRequest = PageRequest.of(pageNo - 1, pageSize);
        Query query = new Query();
        query.addCriteria(Criteria.where("activityId").is(activityId));
        if (StringUtils.isNotBlank(activityChannelStatisticsQueryReq.getChannelName())) {
            Pattern pattern = Pattern.compile("^.*" + activityChannelStatisticsQueryReq.getChannelName() + ".*$",
                    Pattern.CASE_INSENSITIVE);
            query.addCriteria(Criteria.where("channelName").regex(pattern));
        }
        long count = this.mongoTemplate.count(query, ActivityChannelStatistics.class);
        if (count == 0) {
            return PageableExecutionUtils.getPage(new ArrayList<>(), pageRequest, () -> count);
        }
        query.with(Sort.by(Sort.Direction.DESC, "id"));
        List<ActivityChannelStatistics> list = this.mongoTemplate.find(query.with(pageRequest),
                ActivityChannelStatistics.class);
        list.stream().forEach(activityChannelStatistics -> {
            String channelCode = activityChannelStatistics.getChannelCode();
            activityChannelStatistics.setPvCount(setPV(activityId, channelCode, 0L));
            activityChannelStatistics.setUvCount(setUV(activityId, channelCode, 0L));
            String wechatUrl = "";
            String wechatProgressUrl = "";
            if ("contest-plus".equals(activityInfo.getType())) {
                wechatUrl = String.format(this.activityContestPluUrl, activityInfo.getWechatAppId(),
                        activityInfo.getId(), activityInfo.getThemeColor(), channelCode);
                wechatProgressUrl = String.format(this.activityContestPluUrl, activityInfo.getWechatAppId(),
                        activityInfo.getId(), activityInfo.getThemeColor(), channelCode);
            } else if ("vote".equals(activityInfo.getType())) {
                wechatUrl = String.format(this.activityVoteUrl, activityInfo.getId(), activityInfo.getWechatAppId(),
                        activityInfo.getThemeColor(), activityInfo.getAuthorizeMode(), channelCode);
            } else if ("jinshuju".equals(activityInfo.getType())) {
                PlatformConfig platformConfig = platformConfigService.find();
                String cate = platformConfig.getJinCatalogue();
                long time = System.currentTimeMillis();
                String domain = platformConfig.getJinBizFrontDomain();
                wechatUrl =
                        domain + cate + "/index.html?a=1#/pages/index?scope=snsapi_base&activityId=" + activityInfo.getId() + "&channel=" + channelCode + "&t=" + time;
            } else {
                wechatUrl = String.format(this.activityUrl2, activityInfo.getId(), activityInfo.getWechatAppId(),
                        activityInfo.getThemeColor(), channelCode, activityInfo.getAuthorizeMode());
                wechatProgressUrl = String.format(this.activityProgressUrl, activityInfo.getId(),
                        activityInfo.getThemeColor(), activityInfo.getWechatAppId(),
                        activityInfo.getAuthorizeMode(), channelCode);
            }
            String domain = "";
            String catalogue = "";
            String type = "";
            if (constentActivity.contains(activityInfo.getId())) {
                wechatUrl = String.format(this.activityContestUrl, activityInfo.getWechatAppId(),
                        activityInfo.getId());
                domain = platformConfigService.getContestBizFrontDomain();
                catalogue = platformConfigService.getContestCatalogue();
                type = "C";
                if (wechatUrl.contains("/h5/")) {
                    wechatUrl = wechatUrl.replace("/h5/", "/contest-h5/");
                }
                if (wechatProgressUrl.contains("/h5/")) {
                    wechatProgressUrl = wechatProgressUrl.replace("/h5/", "/contest-h5/");
                }
            } else if ("jinshuju".equals(activityInfo.getType())) {
                PlatformConfig platformConfig = platformConfigService.find();
                catalogue = platformConfig.getJinCatalogue();
                domain = platformConfig.getJinBizFrontDomain();
                type = "J";
            } else {
                domain = platformConfigService.getBizFrontDomain();
                if ("contest-plus".equals(activityInfo.getType())) {
                    catalogue = platformConfigService.getContestPlusCatalogue();
                    type = "C-PLUS";
                } else {
                    catalogue = platformConfigService.getCatalogue();
                    type = "A";
                }
            }
            if ("jinshuju".equals(activityInfo.getType())) {
                activityChannelStatistics.setH5Url(wechatUrl);
            } else {
                activityChannelStatistics.setH5Url(domain + catalogue + platformConfigService.replaceActiveCatalogue(wechatUrl, catalogue,
                        type));
            }
            activityChannelStatistics.setH5ProgressUrl(wechatProgressUrl);
            log.info(":>>> 活动:{},domain:{},catalogue:{},type:{}", activityInfo.getName(), domain, catalogue, type);
            if ("jinshuju".equals(activityInfo.getType())) {
                ChannelPageElementReq req = new ChannelPageElementReq();
                req.setActivityId(activityId);
                req.setChannelCode(channelCode);
                req.setPageKey("jin/pages/index");
                List<ActivityChannelPageElementStatistics> pageElementList = activityChannelPageElementStatisticsService.list(req);
                if (CollectionUtils.isNotEmpty(pageElementList)) {
                    long signUPPageUV = pageElementList.stream().mapToLong(ActivityChannelPageElementStatistics::getUv).sum();
                    BigDecimal signUpCount = BigDecimal.valueOf(activityChannelStatistics.getSignUpCount());
                    BigDecimal uvBig = BigDecimal.valueOf(signUPPageUV);
                    BigDecimal rest = signUpCount.divide(uvBig, 2, BigDecimal.ROUND_HALF_UP);
                    activityChannelStatistics.setSignUpRatio(rest.doubleValue());

                }
            }

        });
        return PageableExecutionUtils.getPage(list, pageRequest, () -> count);
    }

    public void saveOrUpdate(ActivityChannelStatisticsCommandReq commandReq) {
        String activityId = commandReq.getActivityId();
        String channelName = commandReq.getChannelName();
        String id = commandReq.getId();
        String optUserName = commandReq.getOptUserName();
        log.info("【操作活动推广渠道】操作人:{}|活动ID：{}| 渠道名称:{}|id:{}", optUserName, activityId, channelName, id);

        Date now = new Date();
        if (StringUtils.isNotBlank(id)) {
            Query query = new Query();
            query.addCriteria(Criteria.where("id").is(id));
            Update update = new Update();
            update.set("channelName", channelName);
            update.set("updatedTime", now);
            this.mongoTemplate.updateFirst(query, update, ActivityChannelStatistics.class);
            return;
        }
        ActivityChannelStatistics activityChannelStatistics = new ActivityChannelStatistics();
        activityChannelStatistics.setActivityId(activityId);
        activityChannelStatistics.setChannelName(channelName);
        activityChannelStatistics.setChannelCode(RandomStringUtils.randomAlphabetic(6));
        activityChannelStatistics.setCreatedTime(now);
        activityChannelStatistics.setUpdatedTime(now);
        this.mongoTemplate.save(activityChannelStatistics);
    }


    /**
     * 获取微信链接
     *
     * @param activityInfo
     * @return
     */
    private String getWechatUrl(ActivityInfo activityInfo, String channel, String type) {
        switch (type) {
            case "A":
                String wechatUrl1 = String.format(this.activityUrl, activityInfo.getId(),
                        activityInfo.getWechatAppId(), activityInfo.getThemeColor(), activityInfo.getAuthorizeMode(),
                        channel
                ) + "&timestamp=" + System.currentTimeMillis();
                return "%s/%s" + wechatUrl1;
            case "C":
                String wechatUrl = String.format(this.activityContestUrl, activityInfo.getWechatAppId(),
                        activityInfo.getId(), channel) + "&timestamp=" + System.currentTimeMillis();
                return "%s" + wechatUrl;
            case "C-PLUS": {
                String wechatUrlP = String.format(this.activityContestPluUrl, activityInfo.getWechatAppId(),
                        activityInfo.getId(), activityInfo.getThemeColor(), channel) + "&timestamp=" + System.currentTimeMillis();
                return "%s" + wechatUrlP;
            }
            default:
                break;
        }
        return "";
    }

    // PV：按 activityId + channel 累加计数（步长为 inc，可为负数）
    private Long setPV(String activityId, String channel, Long inc) {
        String key = String.format(PV, activityId, channel);
        return redisTemplate.execute((RedisCallback<Long>) connection ->
                connection.incrBy(key.getBytes(StandardCharsets.UTF_8), inc)
        );
    }

    // UV：按 activityId + channel 去重计数（步长为 inc，可为负数）
    private Long setUV(String activityId, String channel, Long inc) {
        String key = String.format(UV, activityId, channel);
        return redisTemplate.execute((RedisCallback<Long>) connection ->
                connection.incrBy(key.getBytes(StandardCharsets.UTF_8), inc)
        );
    }

    private Long setUserUV(String cookie, String activityId, String channel) {
        String key = String.format(USER_UV, activityId, channel, cookie);

        // 使用 SET key 1 NX PX 3600000 并返回是否为新设（推荐，原子且简洁）
        Boolean isNew = redisTemplate.opsForValue().setIfAbsent(
                key,
                "1",
                Duration.ofMillis(3600_000L) // 示例：TTL 1 小时，请替换为你的过期时长
        );
        return isNew ? 1L : 0L;
    }
}
